﻿using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace BToolkit.ExeUtils
{
    [ExecuteInEditMode]
    public class BSlider : MonoBehaviour
    {
        public RectTransform bg;
        public RectMask2D mask;
        public RectTransform fill;
        public BButton handle;
        [Space]
        public bool interactable = true;
        [Range(0, 1)]
        public float value;

        public RectTransform rectTransform { get { return transform as RectTransform; } }
        public Action onStartDrag, onStopDrag;
        public Action<float> onChangeValue;
        private bool isDraging;
        private Vector2 prePos;
        private Canvas canvas;
        private float changeValue = -1;

        private void Awake()
        {
            Init();
            if (Application.isPlaying)
            {
                if (handle)
                {
                    handle.AddDown(OnHandleDown);
                    handle.AddUp(OnHandleUp);
                }
            }
        }

        private void Update()
        {
#if UNITY_EDITOR
            Init();
#endif

            UpdateMask();

            if (isDraging)
            {
                Vector2 pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, canvas);
                float delta = pos.x - prePos.x;
                prePos = pos;
                Vector2 handlePos = handle.rectTransform.anchoredPosition;
                handlePos.x += delta;
                handlePos.x = Mathf.Clamp(handlePos.x, 0f, rectTransform.rect.width);
                handle.rectTransform.anchoredPosition = handlePos;
                value = handlePos.x / rectTransform.rect.width;
            }
        }

        private void Init()
        {
            SetLayout(bg);
            SetLayout(mask.rectTransform);
            SetLayout(fill);
            if (handle)
            {
                handle.rectTransform.anchorMin = new Vector2(0, 0.5f);
                handle.rectTransform.anchorMax = new Vector2(0, 0.5f);
            }
        }

        private void SetLayout(RectTransform trans)
        {
            trans.anchorMin = new Vector2(0, 0);
            trans.anchorMax = new Vector2(1, 1);
            trans.offsetMin = new Vector2(0, 0);
            trans.offsetMax = new Vector2(0, 0);
        }

        private void OnHandleDown()
        {
            if (!interactable) return;

            if (!canvas) canvas = GetComponentInParent<Canvas>();
            prePos = BUtils.ScreenToUGUIPoint(Input.mousePosition, canvas);
            isDraging = true;

            onStartDrag?.Invoke();
        }

        private void OnHandleUp()
        {
            isDraging = false;

            onStopDrag?.Invoke();
        }

        private void UpdateMask()
        {
            Vector4 padding = mask.padding;
            padding.z = rectTransform.rect.width * (1 - value);
            mask.padding = padding;
            if (!isDraging)
            {
                if (handle)
                {
                    handle.rectTransform.anchoredPosition = new Vector2(rectTransform.rect.width * value, 0);
                }
            }
            if (changeValue != value)
            {
                changeValue = value;
                onChangeValue?.Invoke(changeValue);
            }
        }
    }
}